package de.szut.sudoku.gui.sudokufield;

import javax.swing.JPanel;

import de.szut.sudoku.game.field.FieldGroup;
import de.szut.sudoku.game.field.SudokuField;
import de.szut.sudoku.gui.MainFrame;

/**
 * Generator for the visual sudoku field on the GUI
 * 
 * @author Marc Huisinga
 * 
 */
public class SudokuFieldGenerator {
	private JPanel parent;
	private KeyInputListener inputListener;
	private SudokuFieldLabel[][] sudokuButtons;
	private SudokuFieldLabel[][] sudokuNoteButtons;

	public final static int STARTINGPOSITIONX = 20;
	public final static int STARTINGPOSITIONY = 50;

	public final static int DISTANCEBETWEENBUTTONSX = 10;
	public final static int DISTANCEBETWEENBUTTONSY = 10;

	public final static float GAPSFACTOR = (float) 1.15;

	public SudokuFieldLabel[][] getSudokuButtons() {
		return sudokuButtons;
	}

	public void setSudokuButtons(SudokuFieldLabel[][] sudokuButtons) {
		this.sudokuButtons = sudokuButtons;
	}

	public SudokuFieldLabel[][] getSudokuNoteButtons() {
		return sudokuNoteButtons;
	}

	public void setSudokuNoteButtons(SudokuFieldLabel[][] sudokuNoteButtons) {
		this.sudokuNoteButtons = sudokuNoteButtons;
	}

	public SudokuFieldGenerator(JPanel parent) {
		this.parent = parent;
	}

	/**
	 * Loads the sudokufield entirely into the visuals
	 * 
	 * @param field
	 */
	public void loadFieldIntoVisuals(SudokuField field) {
		FieldGroup[] horizontalGroups = field.getHorizontalGroups();
		int xIndex = 0;
		// iterates through every button and refreshes the state and the
		// keylisteners
		for (SudokuFieldLabel[] buttonLine : sudokuButtons) {
			int yIndex = 0;
			for (SudokuFieldLabel button : buttonLine) {
				// sets preset configuration for buttons that are preset
				if (horizontalGroups[xIndex].getStates()[yIndex] != 0) {
					button.setSudokuText(String
							.valueOf(horizontalGroups[xIndex].getStates()[yIndex]));
					button.setForeground(SudokuFieldLabel.PRESETTEXTCOLOR);
					button.removeKeyListener(inputListener);
				}

				yIndex++;
			}
			xIndex++;
		}
		// refreshes the frame
		MainFrame.getInstance().revalidate();
		MainFrame.getInstance().repaint();
	}

	/**
	 * Adds a field to the visuals
	 * 
	 * @param field
	 */
	public void addFieldIntoVisuals(SudokuField field) {
		FieldGroup[] horizontalGroups = field.getHorizontalGroups();
		int xIndex = 0;
		// iterates through every button and refreshes the state
		for (SudokuFieldLabel[] buttonLine : sudokuButtons) {
			int yIndex = 0;
			for (SudokuFieldLabel button : buttonLine) {
				if (horizontalGroups[xIndex].getStates()[yIndex] != 0) {
					button.setSudokuText(String
							.valueOf(horizontalGroups[xIndex].getStates()[yIndex]));
				}

				yIndex++;
			}
			xIndex++;
		}
		// refreshes the frame
		MainFrame.getInstance().revalidate();
		MainFrame.getInstance().repaint();
	}

	public static int getSudokuFieldWidth() {
		return Math.round(STARTINGPOSITIONX + 9 * SudokuButton.WIDTH + 6
				* DISTANCEBETWEENBUTTONSX + 2 * DISTANCEBETWEENBUTTONSX
				* GAPSFACTOR);

	}

	public static int getSudokuFieldHeight() {
		return Math.round(STARTINGPOSITIONY + 9 * SudokuButton.HEIGHT + 6
				* DISTANCEBETWEENBUTTONSY + 2 * DISTANCEBETWEENBUTTONSY
				* GAPSFACTOR);
	}

	/**
	 * Clears the visual sudoku field
	 */
	public void clearSudokuField() {
		// resets the state of all sudokubuttons
		for (SudokuFieldLabel[] currentButtonLine : sudokuButtons) {
			for (SudokuFieldLabel currentLabel : currentButtonLine) {
				currentLabel.setText("");
				currentLabel.setVisible(false);
				currentLabel.setForeground(SudokuFieldLabel.DEFAULTTEXTCOLOR);
				if (currentLabel.getKeyListeners().length == 1) {
					currentLabel.addKeyListener(inputListener);
				}
			}
		}
		// resets the state of all notebuttons
		for (SudokuFieldLabel[] currentButtonLine : sudokuNoteButtons) {
			for (SudokuFieldLabel currentLabel : currentButtonLine) {
				currentLabel.setText("");
				currentLabel.setVisible(false);
			}
		}

		MainFrame.getInstance().revalidate();
		MainFrame.getInstance().repaint();
	}

	/**
	 * Generates the sudoku field
	 */
	public void generateSudokuField() {
		int[] sudokuButtonSize = { SudokuButton.WIDTH, SudokuButton.HEIGHT };
		int[] noteButtonSize = { SudokuNoteKey.WIDTH, SudokuNoteKey.HEIGHT };
		int[] startPos = { STARTINGPOSITIONX, STARTINGPOSITIONY };
		int[] buttonOffset = { DISTANCEBETWEENBUTTONSX, DISTANCEBETWEENBUTTONSY };
		int[] currentPos = { startPos[0], startPos[1] };
		sudokuButtons = new SudokuFieldLabel[9][9];
		SudokuButtonClickListener clickListener = new SudokuButtonClickListener();
		SudokuButtonKeyListener sudokuKeyListener = new SudokuButtonKeyListener(
				clickListener, sudokuButtons);
		inputListener = new KeyInputListener(sudokuButtons);
		int[] realOffset = { sudokuButtonSize[0] + buttonOffset[0],
				sudokuButtonSize[1] + buttonOffset[1] };
		int[] currentIndex = new int[2];
		// generates the sudoku buttons
		for (currentIndex[0] = 0; currentIndex[0] != 9; currentIndex[0]++) {
			for (currentIndex[1] = 0; currentIndex[1] != 9; currentIndex[1]++) {
				sudokuButtons[currentIndex[0]][currentIndex[1]] = new SudokuButton(
						currentPos[0], currentPos[1], sudokuKeyListener,
						clickListener);
				sudokuButtons[currentIndex[0]][currentIndex[1]]
						.addKeyListener(inputListener);
				sudokuButtons[currentIndex[0]][currentIndex[1]]
						.setVisible(false);
				parent.add(sudokuButtons[currentIndex[0]][currentIndex[1]]);
				// adds a gap if needed
				if ((currentIndex[1] + 1) % 3 == 0) {
					currentPos[0] += GAPSFACTOR * realOffset[0];
				} else {
					currentPos[0] += realOffset[0];
				}
			}
			// adds a gap if needed
			if ((currentIndex[0] + 1) % 3 == 0) {
				currentPos[1] += GAPSFACTOR * realOffset[1];
			} else {
				currentPos[1] += realOffset[1];
			}
			currentPos[0] = startPos[0];
		}

		currentPos[0] = startPos[0];
		currentPos[1] = startPos[1];

		sudokuNoteButtons = new SudokuFieldLabel[18][18];
		SudokuNoteKeyListener noteKeyListener = new SudokuNoteKeyListener();
		// generates the note buttons
		for (currentIndex[0] = 0; currentIndex[0] != 18; currentIndex[0]++) {
			for (currentIndex[1] = 0; currentIndex[1] != 18; currentIndex[1]++) {
				sudokuNoteButtons[currentIndex[0]][currentIndex[1]] = new SudokuNoteKey(
						currentPos[0], currentPos[1], noteKeyListener,
						clickListener);
				sudokuNoteButtons[currentIndex[0]][currentIndex[1]]
						.setVisible(false);
				parent.add(sudokuNoteButtons[currentIndex[0]][currentIndex[1]]);
				parent.setComponentZOrder(
						sudokuNoteButtons[currentIndex[0]][currentIndex[1]], 0);
				// adds a large gap
				if ((currentIndex[1] + 1) % 6 == 0) {
					currentPos[0] += GAPSFACTOR * realOffset[0]
							- sudokuButtonSize[0] + noteButtonSize[0];
					// adds a small gap
				} else if ((currentIndex[1] + 1) % 2 == 0) {
					currentPos[0] += buttonOffset[0] + noteButtonSize[0];
				} else {
					currentPos[0] += sudokuButtonSize[0] - noteButtonSize[0];
				}
			}
			// adds a large gap
			if ((currentIndex[0] + 1) % 6 == 0) {
				currentPos[1] += GAPSFACTOR * realOffset[1]
						- sudokuButtonSize[1] + noteButtonSize[1];
				// adds a small gap
			} else if ((currentIndex[0] + 1) % 2 == 0) {
				currentPos[1] += buttonOffset[1] + noteButtonSize[1];
			} else {
				currentPos[1] += sudokuButtonSize[1] - noteButtonSize[1];
			}
			currentPos[0] = startPos[0];
		}
	}
}
